package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.qo.QueryCourseBaseModel;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.CourseMarketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {

    @Autowired
    private CourseBaseMapper courseBaseMapper;
    @Autowired
    private CourseMarketService courseMarketService;


    public List<CourseBase> queryAll() {
        List<CourseBase> result = courseBaseMapper.selectList(Wrappers.emptyWrapper());
        return result;
    }

    public PageVO queryCourseBaseList(PageRequestParams params, QueryCourseBaseModel model,Long companyId) {
        // 1.判断业务数据
        // 1.1 判断分页数据
        if (params.getPageNo() < 1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (params.getPageSize() < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }

        // 1.2 判断条件查询数据（如果查询条件有数据，在sql中添加条）
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
         if (StringUtil.isNotBlank(model.getAuditStatus())) {
             // 添加的审核状态条件（eq）
             queryWrapper.eq(CourseBase::getAuditStatus, model.getAuditStatus());
         }

         if (StringUtil.isNotBlank(model.getCourseName())) {
             // 添加的课程名称条件（like）
             queryWrapper.like(CourseBase::getName, model.getCourseName());
         }
         queryWrapper.eq(CourseBase::getCoursePubId,companyId);
         queryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCode());

        // 2.创建分页数据
        Page<CourseBase> page = new Page<>(params.getPageNo(),params.getPageSize());

        // 3.根据分页和查询调价查询list数据
        Page<CourseBase> pageResult = this.page(page, queryWrapper);

        List<CourseBase> records = pageResult.getRecords();
        List<CourseBaseDTO> dtos = CourseBaseConvert.INSTANCE.entitys2dtos(records);

        long total = pageResult.getTotal();

        // 4.将查询结果封装到PageVO中
        /*
         * PageVO构造方法：
         *   1.当前页的集合数据
         *   2.数据库中的总条数
         *   3.当前页码
         *   4.每页条数
         * */
        PageVO pageVO = new PageVO(dtos,total,params.getPageNo(),params.getPageSize());

        return pageVO;
    }


    /*
    业务分析:
    1.是否开启事务
        新增操作需要开启事务
        如果新增操作只会操作一张表而且只会操作一次，那么可以忽略事务
    2.判断关键数据
        课程基础信息
            关键数据:表中内容的必要数据，无此数据代表数据不完整
            关键数据的来源:
            1,数据库的约束
                不能为空的字段
            2.前端页面中必要数据
                用小红点来显示
            3.接口文档:Yapi
                会体现出必要的数据
    3.将dto转为po数据，并且赋值审核状态的默认值
        保存:未提交
    4.保存数据
        4.1保存课程基础信息
            判断保存的结果
        4.2保存课程营销信息
            判断保存的结果
    5.将数据库的最新数据转为dto并返回
     */
    @Transactional
    public CourseBaseDTO createCourseBase(CourseBaseDTO dto) {
        //1.是否开启事务
        //   因为操作两个表，所以需要加事务管理

        //2.判断关键数据
        //2.1,数据库的约束
        //2.2.前端页面中必要数据
        // company_id/name/mt/st/grade(课程等级)/teachmode（教育模式）/audit_status（审核状态）
        verifyCourseMsg(dto);

        //如果课程是收费的，收费金额也需要传递
        if(CourseChargeEnum.CHARGE_YES.getCode().equals(dto.getCharge())){
            if(ObjectUtils.isEmpty(dto.getPrice())){
                throw new RuntimeException("收费课程的价格不能为空");
            }
        }

        //3.将dto转为po数据，并且赋值审核状态的默认值
        //保存:未提交
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2entity(dto);
        courseBase.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());

        //4.保存数据
        //4.1保存课程基础信息
                //判断保存的结果
        int line1 = courseBaseMapper.insert(courseBase);
        if(line1<=0){
            throw new RuntimeException("课程基本信息保存失败");
        }

        //4.2保存课程营销信息
                //判断保存的结果
        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setCourseId(courseBase.getId());
        courseMarket.setCharge(dto.getCharge());
        courseMarket.setPrice(dto.getPrice());

        boolean bool = courseMarketService.save(courseMarket);
        if(!bool){
            throw new RuntimeException("课程营销信息保存失败");
        }

        //5.将数据库的最新数据转为dto并返回
        CourseBaseDTO newDto = CourseBaseConvert.INSTANCE.entity2dto(courseBase);

        newDto.setCharge(courseMarket.getCharge());
        newDto.setPrice(courseMarket.getPrice());

        return newDto;
    }


    /*
    1.判断关键数据
        判断课程id是否有值
        判断是否有传过来的值
    2.获取po数据
    3.跟据返回信息判断是否给前端返回数据
        是否存在数据
        课程信息是否被删除
    4.将数据库的最新数据转为dto并返回
     */
    public CourseBaseDTO getCourseBaseById(Long courseBaseId,Long companyId) {
        //1.判断关键数据
        if(ObjectUtils.isEmpty(courseBaseId) || ObjectUtils.isEmpty(companyId)){
            throw new RuntimeException(CommonErrorCode.E_100101.getDesc());
        }

        //2.获取po数据
        CourseBase courseBase = verifyCourseBusiness(courseBaseId, companyId);

        LambdaQueryWrapper<CourseMarket> wrapper2 = Wrappers.lambdaQuery(CourseMarket.class);
        wrapper2.eq(CourseMarket::getCourseId,courseBaseId);
        CourseMarket courseMarket = courseMarketService.getOne(wrapper2);

        //4.将数据库的最新数据转为dto并返回
        CourseBaseDTO courseBaseDTO = CourseBaseConvert.INSTANCE.entity2dto(courseBase);
        courseBaseDTO.setCharge(courseMarket.getCharge());
        courseBaseDTO.setPrice(courseMarket.getPrice());

        return courseBaseDTO;
    }

    /*
    1.判断关键数据
    2.判断业务数据
    3.把dto传承po
    4.修改数据
    5.将数据转成dto并返回
     */
    @Transactional
    public CourseBaseDTO modifyCourseBase(CourseBaseDTO dto) {

        //1.判断关键数据
        verifyCourseMsg(dto);

        //2.判断业务数据
        CourseBase courseBase = verifyCourseBusiness(dto.getCourseBaseId(), dto.getCompanyId());

        String auditStatus = courseBase.getAuditStatus();
        if(CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ){
            throw new RuntimeException("课程审核状态异常");
        }

        //3.把dto传承po
        //4.修改数据
        CourseBase cbpo = CourseBaseConvert.INSTANCE.dto2entity(dto);
        boolean b = this.updateById(cbpo); //也可以使用 courseBaseMapper
        if(!b){
            throw new RuntimeException("修改基本课程信息失败");
        }

        LambdaUpdateWrapper<CourseMarket> wrapper = Wrappers.lambdaUpdate(CourseMarket.class);
        wrapper.eq(CourseMarket::getCourseId,cbpo.getId());
        wrapper.set(CourseMarket::getCharge,dto.getCharge());

        BigDecimal price = new BigDecimal(0);
        if(CourseChargeEnum.CHARGE_YES.getCode().equals(dto.getCharge())){
            price = dto.getPrice();
        }
        wrapper.set(CourseMarket::getPrice,price);

        boolean b2 = courseMarketService.update(wrapper);
        if(!b2){
            throw new RuntimeException("修改课程营销失败");
        }

        //5.将数据转成dto并返回
        CourseBase poById = this.getById(dto.getCourseBaseId());
        CourseBaseDTO dtoByPo = CourseBaseConvert.INSTANCE.entity2dto(poById);
        dtoByPo.setCharge(dto.getCharge());
        dtoByPo.setPrice(dto.getPrice());

        return dtoByPo;
    }


    /*
    1.判断关键数据
    2.判断业务数据（获取po）
    3.修改数据
    4.获取数据并返回
     */
    public Boolean deleteCourseBaseById(Long courseBaseId, Long companyId) {
        //1.判断关键数据
        if(ObjectUtils.isEmpty(courseBaseId) ||
        ObjectUtils.isEmpty(companyId)){
            throw new RuntimeException(CommonErrorCode.E_100101.getDesc());
        }

        //2.判断业务数据
        LambdaQueryWrapper<CourseBase> wrapper = Wrappers.lambdaQuery(CourseBase.class);
        wrapper.eq(CourseBase::getId,courseBaseId);
        wrapper.eq(CourseBase::getCompanyId,companyId);
        CourseBase cbpo = this.getOne(wrapper);

        if(CommonEnum.DELETE_FLAG.getCodeInt().equals(cbpo.getStatus())){
            throw new RuntimeException("该信息已被删除");
        }

        //3.修改数据
        //4.获取数据并返回
        LambdaUpdateWrapper<CourseBase> wrapper1 = Wrappers.lambdaUpdate(CourseBase.class);
        wrapper1.eq(CourseBase::getId,courseBaseId);
        wrapper1.eq(CourseBase::getCompanyId,companyId);
        wrapper1.set(CourseBase::getStatus,CommonEnum.DELETE_FLAG.getCode());
        wrapper1.set(CourseBase::getChangeDate, LocalDateTime.now());
        boolean bool = this.update(wrapper1);

        if(!bool){
            throw new RuntimeException(ContentErrorCode.E_120017.getDesc());
        }

        return bool;
    }

    private void verifyCourseMsg(CourseBaseDTO dto){
        if(ObjectUtils.isEmpty(dto.getCompanyId())){
            throw new RuntimeException("公司id不能为空");
        }
        if(StringUtil.isBlank(dto.getName())){
            throw new RuntimeException("课程名称不能为空");
        }
        if(StringUtil.isBlank(dto.getMt())){
            throw new RuntimeException("课程大类不能为空");
        }
        if(StringUtil.isBlank(dto.getSt())){
            throw new RuntimeException("课程小类不能为空");
        }
        if(StringUtil.isBlank(dto.getGrade())){
            throw new RuntimeException("课程等级不能为空");
        }
        if(StringUtil.isBlank(dto.getTeachmode())){
            throw new RuntimeException("课程教学模式不能为空");
        }
        if(StringUtil.isBlank(dto.getUsers())){
            throw new RuntimeException("使用人群不能为空");
        }
        if(StringUtil.isBlank(dto.getCharge())){
            throw new RuntimeException("课程收费规则不能为空");
        }
    }

    private CourseBase verifyCourseBusiness(Long courseBaseId,Long companyId){
        //2.获取po数据
        LambdaQueryWrapper<CourseBase> wrapper = Wrappers.lambdaQuery(CourseBase.class);
        wrapper.eq(CourseBase::getId,courseBaseId);
        wrapper.eq(CourseBase::getCompanyId,companyId);
        CourseBase courseBase = courseBaseMapper.selectOne(wrapper);

        //3.跟据返回信息判断是否给前端返回数据
        if(ObjectUtils.isEmpty(courseBase)){
            throw new RuntimeException("未获取对应的课程信息");
        }
        if(CommonEnum.DELETE_FLAG.getCodeInt().equals(courseBase.getStatus())){
            throw new RuntimeException("该课程已被删除");
        }

        return courseBase;
    }

}